/**
 * 文件名：@LengthValidator.java <br/>
 * 包名：cn.efunbox.afw.core.validation <br/>
 * 项目名：afw-core <br/>
 * @author xtwin <br/>
 */
package cn.efunbox.afw.core.validation;

import java.util.Collection;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import cn.efunbox.afw.core.exception.SystemException;
import cn.efunbox.afw.core.exception.ValidationException;
import cn.efunbox.afw.core.mvc.context.Context;
import cn.efunbox.afw.core.util.StringUtil;

/**
 * 类名：LengthValidator  <br />
 *
 * 功能：长度校验 <br />
 * 
 * 	<pre>
 * 		长度计算规则：
 * 			1、数组
 * 				取其length属性值
 * 			2、集合
 * 				取其size()方法的返回值
 * 			3、字符串
 * 				若：relyByte为true，则执行字符串的getBytes(encoding).length
 * 				若：relyByte为false，则取length()方法的返回值
 * 	</pre>
 *
 * @author xtwin <br />
 * 创建时间：2015年12月2日 下午3:17:46  <br />
 * @version 2015年12月2日
 */
public class LengthValidator extends AbstractValidator {
	
	// 日志记录器
	private static final Log logger = LogFactory.getLog(LengthValidator.class);
	
	// 最大长度，-1为不限
	private int maximum = -1;
	
	// 最小长度，-1为不限
	private int minimum = -1;
	
	// 按字节计算长度，默认为false
	private boolean relyByte;
	
	// 在计算字节长度时，使用的编码方式，默认为UTF-8
	private String encoding = "UTF-8";
	
	/**
	 * 构造方法
	 */
	public LengthValidator() {
		super("validation.error.length");
	}

	/**
	 * 功能: <br/>
	 * 
	 * 重写：xtwin <br/>
	 * 
	 * @version ：2015年12月2日 下午3:18:09<br/>
	 * 
	 * @param field
	 * @param value
	 * @param message
	 * @param config
	 * @throws Exception <br/>
	 * @see cn.efunbox.afw.core.validation.AbstractValidator#doValidate(cn.efunbox.afw.core.mvc.context.Context, java.lang.String, java.lang.Object, java.lang.String, java.lang.Object)
	 */
	@Override
	protected void doValidate(Context context, String field, Object value, String message, Object config) throws Exception {
		int _max = maximum;
		int _min = minimum;
		boolean _relyByte = relyByte;
		String _encoding = encoding;
		
		if (null != config) {
			// 重写了配置，完整的参数为：minimum, maximum, bychar, encoding
			String[] cfgs = ((String) config).split(",");
			
			// 取出配置参数的长度
			int len = cfgs.length;
			
			// 
			if (len > 0 && ! StringUtil.isEmpty(cfgs[0])) {
				_min = Integer.parseInt(cfgs[0]);
			}
			
			if (len > 1 && ! StringUtil.isEmpty(cfgs[1])) {
				_max = Integer.parseInt(cfgs[1]);
			}
			
			if (len > 2 && ! StringUtil.isEmpty(cfgs[2])) {
				_relyByte = Boolean.parseBoolean(cfgs[2]);
			}
			
			if (len > 3 && ! StringUtil.isEmpty(cfgs[3])) {
				_encoding = cfgs[3];
			}
		}
		
		// 根据配置，计算长度
		int length = parseLength(value, _relyByte, _encoding);
		
		if (logger.isDebugEnabled()) {
			logger.debug("parse length is : " + length);
		}
		
		/*// 执行长度检查
		if (_min <= length && (_max == -1 || length <= _max)) {
			return value;
		}*/
		
		// 报错
		if (length < _min || (_max != -1 && length > _max)) {
			if (null != code) {
				throw new ValidationException(null != message ? message : this.message, code, new Object[] { field });
			} else {
				throw new ValidationException(null != message ? message : this.message, new Object[] { field });
			}
		}
	}

	/**
	 * 
	 * 功能：解析出长度 <br/>
	 *
	 * @author xtwin <br/>
	 * @version 2015年12月2日 下午3:38:05 <br/>
	 */
	protected int parseLength(Object value, boolean _relyByte, String encoding) throws Exception {
		int length = 0;
		
		if (null != value) {
			if (value instanceof String) {
				if (_relyByte) {
					length = ((String) value).length();
				} else {
					length = ((String) value).getBytes(encoding).length;
				}
			} else if (value instanceof Object[]) {
				length = ((Object[]) value).length;
			} else if (value instanceof Collection) {
				length = ((Collection<?>) value).size();
			} else if (value instanceof Map) {
				length = ((Map<?, ?>) value).size();
			} else {
				throw new SystemException("system.error.not.support", new Object[] { value.getClass().getName() });
			}
		}
		
		return length;
	}

	/**
	 * @version 2015年12月2日-下午3:44:27
	 */
	public void setMaximum(int maximum) {
		this.maximum = maximum;
	}

	/**
	 * @version 2015年12月2日-下午3:44:27
	 */
	public void setMinimum(int minimum) {
		this.minimum = minimum;
	}

	/**
	 * @version 2015年12月2日-下午3:44:27
	 */
	public void setRelyByte(boolean relyByte) {
		this.relyByte = relyByte;
	}

	/**
	 * @version 2015年12月2日-下午3:44:27
	 */
	public void setEncoding(String encoding) {
		this.encoding = encoding;
	}
}
